//
// Created by DELL on 24-9-20.
//
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "esp_log.h"

#include "wind_connect.h"
#include "cm_common.h"
#include "jkbytes.h"
#include "wind_protocol_wrap.h"

#define size_t int

#define ECHO_UART_PORT_NUM 1
#define ECHO_UART_BAUD_RATE 230400

#define BUF_SIZE 1024

enum {
    CONNECT_READ_NONE = 0,
    CONNECT_READ_START = 1,
    CONNECT_READ_CMD = 2,
    CONNECT_READ_SUBCMD = 3,
    CONNECT_READ_ARGS = 4,
};

typedef struct {
    int cmd;
    int sub_cmd;

    int angle_door;
    int angle_image;
    int door_timeout;
} ConnectCmd;

typedef struct {
    int       exited;

    char dev[32];
    int bs;

    int read_status;
    ConnectCmd cur_cmd;
} WindConnectHandler;

static WindConnectHandler s_wind_handler;


static void wind_connect_status_changed(int st)
{
    ESP_LOGI("connect", "wind_connect_status_changed [%d] => [%d]", s_wind_handler.read_status, st);
    s_wind_handler.read_status = st;
}

int uart_send_data(char *data, int len)
{
    return uart_write_bytes(ECHO_UART_PORT_NUM, (const void *) data, len);
}

int uart_read_data(char *data, int len)
{
    int ret = uart_read_bytes(ECHO_UART_PORT_NUM, (void*)data, len, 100 / portTICK_PERIOD_MS);
    return ret;
}

static int uart_send_data_wrap(char *buf, int len)
{
    int r = uart_send_data(buf, len);
    ESP_ERROR_CHECK(uart_wait_tx_done(ECHO_UART_PORT_NUM, 10));
    return r;
}

static int wind_connect_transfer_image_file(const char *filename, size_t file_size)
{
    int remain = file_size;
    char buf[1024] = {0};
    int transfered = 1024;
    int block = 1024;
    ESP_LOGD("wind", "start to recv image");
    while (remain > 0)
    {
        if (remain < 1024)
        {
            block = remain;
        }
        int ret = uart_read_data(buf, block);
        transfered += ret;
        remain -= ret;
        ESP_LOGI("wind", "buf [%x %x %x %x] [%x %x %x %x]",
                 buf[0], buf[1], buf[2], buf[3],
                 buf[ret-4], buf[ret-3], buf[ret-2], buf[ret - 1]);
    }
    ESP_LOGI("wind", "transfer image file [%s] success of len [%zu]", filename, transfered);

    return 0;
}

static int wind_connect_find_transfer_image()
{
    char data[8] = {0};
    int c = 0;
    int count = 0, angle = 0;
    int step = 0;
    int ret = 0;

    char datar[8] = {0};
    LOGD("get image size");
    while (1) {
        // read
        ret = uart_read_data(datar, 5);
        if (ret > 0) {
            memcpy(&count, datar, 4);
            memcpy(&angle, datar + 4, 1);
            ESP_LOGI("wind", "find image count [%d] angle [%d]", count, angle);
            break;
        }
        usleep(10000);
    }

    ESP_LOGI("wind", "send request for get image");
    usleep(50000);
    // send request
    data[0] = WIND_PROTOCOL_HEAD_PREFIX;
    data[1] = WIND_PROTOCOL_CMD_GET_IMAGE;
    data[2] = 0;
    save_int_to_hex(count, (unsigned char*)(data + 3));
    data[7] = angle;
    int d = 0;
    while (d++ < 1)
    {
        ret = uart_send_data_wrap(data, 8);

        usleep(50000);

        LOGD("send request out len [%d]", ret);
    }
    ESP_LOGI("wind", "get image start");
    // read of image size

    int image_size = 0;
    step = 0;
    while (1) {
        if (step == 0)
        {
            ret = uart_read_data(data, 3);
            if (ret > 0) {
                if (data[0] == WIND_PROTOCOL_HEAD_RESP_PREFIX && data[1] == WIND_PROTOCOL_CMD_GET_IMAGE)
                {
                    step = 1;
                }
            }
        } else if (step == 1) {
            ret = uart_read_data(data, 5);
            if (ret >= 5)
            {
                memcpy(&image_size, data + 1, 4);
                ESP_LOGI("wind", "image size = [%d]", image_size);
                break;
            }
        }      
    }

    wind_connect_transfer_image_file("image.jpg", image_size);
    return 0;
}

static int wind_connect_recv_data_parse_and_do()
{
    if (s_wind_handler.cur_cmd.cmd == WIND_PROTOCOL_CMD_GET_VERSION)
    {
        char resp[10] = {0};
        uart_read_data(resp, 3);
        LOGD("recv version [%x %x %x]", resp[0], resp[1], resp[2]);
        wind_connect_status_changed(CONNECT_READ_NONE);
    }
    else if (s_wind_handler.cur_cmd.cmd == WIND_PROTOCOL_CMD_SET_ANGLE_IMAGE)
    {
        if (s_wind_handler.cur_cmd.sub_cmd == WIND_PROTOCOL_CMD_SUB_SET) {
            
        } else {
            
        }
        wind_connect_status_changed(CONNECT_READ_NONE);
    } else if (s_wind_handler.cur_cmd.cmd == WIND_PROTOCOL_CMD_GET_IMAGE)
    {
        LOGD("response get image\n");
    } else if (s_wind_handler.cur_cmd.cmd == WIND_PROTOCOL_CMD_REPORT_DOOR_CLOSE)
    {
        LOGD("door close, start to get image");
        ESP_LOGI("wind", "door close, start to get image");
        wind_connect_find_transfer_image();
        wind_connect_status_changed(CONNECT_READ_NONE);
    }
    return 0;
}

static int wind_connect_recv_data_continue()
{
    static int only_once = 0;
    switch (s_wind_handler.read_status) {
        case CONNECT_READ_NONE:
        {
            if (only_once == 0) {
                only_once = 1;
                char tdata[4] = {0};
                tdata[0] = WIND_PROTOCOL_HEAD_PREFIX;
                tdata[1] = WIND_PROTOCOL_CMD_GET_VERSION;
                tdata[2] = 0;
                int r = uart_send_data_wrap(tdata, 3);
                ESP_LOGI("connect", "send version and read again len [%d]\n", r);
                usleep(1000000);
            }
            char buf[2] = {0};
            int ret = uart_read_data(buf, 1);
            if (ret > 0)
            {
                if (wind_protocol_is_head((unsigned char*)buf, 2))
                {
                    wind_connect_status_changed(CONNECT_READ_CMD);
                }
                else
                {
                    ESP_LOGI("connect", "unknown recv data [%x]", buf[0]);
                }
            }
        }
            break;
        case CONNECT_READ_START:
            wind_connect_status_changed(CONNECT_READ_NONE);
            break;
        case CONNECT_READ_CMD: {
            unsigned char buf[2] = {0};
            int ret = uart_read_data((char*)buf, 1);
            if (ret > 0) {
                if (wind_protocol_is_cmd_get_image(buf, 2)) {
                    wind_connect_status_changed(CONNECT_READ_SUBCMD);
                    s_wind_handler.cur_cmd.cmd = WIND_PROTOCOL_CMD_GET_IMAGE;
                } else if (wind_protocol_is_cmd_get_version(buf, 2)) {
                    wind_connect_status_changed(CONNECT_READ_SUBCMD);
                    s_wind_handler.cur_cmd.cmd = WIND_PROTOCOL_CMD_GET_VERSION;
                } else if (wind_protocol_is_cmd_set_angle_image(buf, 2)){
                    wind_connect_status_changed(CONNECT_READ_SUBCMD);
                    s_wind_handler.cur_cmd.cmd = WIND_PROTOCOL_CMD_SET_ANGLE_IMAGE;
                } else if (wind_protocol_is_cmd_set_angle_open(buf, 2)){
                    wind_connect_status_changed(CONNECT_READ_SUBCMD);
                    s_wind_handler.cur_cmd.cmd = WIND_PROTOCOL_CMD_SET_ANGLE_OPEN;
                } else if (wind_protocol_is_cmd_set_open_timeout(buf, 2)){
                    wind_connect_status_changed(CONNECT_READ_SUBCMD);
                    s_wind_handler.cur_cmd.cmd = WIND_PROTOCOL_CMD_SET_OPEN_TIMEOUT;
                } else if (wind_protocol_is_cmd_report_door_close(buf, 2)) {
                    wind_connect_status_changed(CONNECT_READ_SUBCMD);
                    s_wind_handler.cur_cmd.cmd = WIND_PROTOCOL_CMD_REPORT_DOOR_CLOSE;
                }
            }
        }
            break;
        case CONNECT_READ_SUBCMD:{
            char buf[2] = {0};
            int ret = uart_read_data(buf, 1);
            if (ret > 0) {
                s_wind_handler.cur_cmd.sub_cmd = wind_protocol_is_sub_cmd_set((unsigned char*)buf, 2);

                wind_connect_status_changed(CONNECT_READ_ARGS);
            }
        }
            break;
        case CONNECT_READ_ARGS:
            wind_connect_recv_data_parse_and_do();
            break;
    }
    return 0;
}

int wind_connect_transfer()
{
    wind_connect_recv_data_continue();
    return 0;
}

int wind_connect_init_in_thread()
{
    esp_log_level_set("wind", ESP_LOG_DEBUG);
        /* Configure parameters of an UART driver,
     * communication pins and install the driver */
    uart_config_t uart_config = {
        .baud_rate = ECHO_UART_BAUD_RATE,
        .data_bits = UART_DATA_8_BITS,
        .parity    = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_DEFAULT,
    };
    int intr_alloc_flags = 0;
    ESP_ERROR_CHECK(uart_driver_install(ECHO_UART_PORT_NUM, BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags));
    ESP_ERROR_CHECK(uart_param_config(ECHO_UART_PORT_NUM, &uart_config));
    ESP_ERROR_CHECK(uart_set_mode(ECHO_UART_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX));
//    ESP_ERROR_CHECK(uart_set_pin(ECHO_UART_PORT_NUM, 10, 11, 2, 3));
    ESP_ERROR_CHECK(uart_set_pin(ECHO_UART_PORT_NUM, 17, 18, 16, 3));

    s_wind_handler.exited = 0;
    wind_connect_status_changed(CONNECT_READ_NONE);
    LOGD("wind_connect thread init");
    return 0;
}

int wind_connect_deinit()
{
    s_wind_handler.exited = 1;
    LOGD("wind_connect thread deinit");
    return 0;
}

int wind_connect_send_data(const char *data, int len)
{
    return 0;
}
